package com.gridmobi.xrtb.handler.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.gridmobi.xrtb.common.CTZ;
import com.gridmobi.xrtb.common.DeviceLogUtil;
import com.gridmobi.xrtb.common.GeoMap;
import com.gridmobi.xrtb.component.lucene.BidIndex;
import com.gridmobi.xrtb.component.lucene.SimpleBidData;
import com.gridmobi.xrtb.domain.adn.OsE;
import com.gridmobi.xrtb.domain.dsp.DspTrackLog;
import com.gridmobi.xrtb.domain.dsp.common.AppConstant;
import com.gridmobi.xrtb.domain.dsp.common.Patten;
import com.gridmobi.xrtb.domain.dsp.common.enums.*;
import com.gridmobi.xrtb.dspcounter.DspCounterHandler;
import com.gridmobi.xrtb.handler.DeviceInfo;
import com.gridmobi.xrtb.handler.IDFilter;
import com.gridmobi.xrtb.handler.monitor.IpMonitor;
import com.gridmobi.xrtb.handler.monitor.RtbStatus;
import com.gridmobi.xrtb.handler.monitor.SimpleData;
import com.gridmobi.xrtb.job.SourceManager;
import com.gridmobi.xrtb.model.BidExt;
import com.gridmobi.xrtb.model.alg.*;
import com.gridmobi.xrtb.model.openrtb23.*;
import com.gridmobi.xrtb.model.openrtbnative11.req.Asset;
import com.gridmobi.xrtb.model.openrtbnative11.req.Request;
import com.gridmobi.xrtb.model.openrtbnative11.resp.Image;
import com.gridmobi.xrtb.model.openrtbnative11.resp.Link;
import com.gridmobi.xrtb.model.openrtbnative11.resp.Response;
import com.gridmobi.xrtb.model.openrtbnative11.resp.Title;
import com.gridmobi.xrtb.model.rtb.*;
import com.gridmobi.xrtb.util.ChannelHelper;
import com.gridmobi.xrtb.util.RtbUtil;
import org.apache.commons.lang3.StringUtils;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.FloatPoint;
import org.apache.lucene.document.IntPoint;
import org.apache.lucene.document.LongPoint;
import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.Term;
import org.apache.lucene.search.*;
import org.apache.lucene.util.BytesRef;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import org.springframework.web.client.RestTemplate;

import java.io.IOException;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.LongAdder;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.Stream;

/**
 * @author huangyongchao
 */
@Component
public class BidHandler {

    @Autowired
    DspCounterHandler dspCounterHandler;

    @Autowired
    BidIndex bidIndex;
//
//    @Autowired
//    VideoSourceManager videoSourceManager;
//
//    @Autowired
//    ImageSourceManager imageSourceManager;

    @Autowired
    SourceManager sourceManager;

    @Autowired
    IDFilter idFilter;

    public static String BID_SEAT = "seat";
    public static String IMP_PREFIX = "direct:";

    public static String BID_CUR_UNIT = "USD";
    private static final Logger logger = LoggerFactory.getLogger(DataSynchHandlerImpl.class);
    private static final Logger errorlogger = LoggerFactory.getLogger("error");
    private static final Logger collectLogger = LoggerFactory.getLogger("com.gridmobi.xrtb.handler.impl.BidHandler");
    private static final Logger reqlogger = LoggerFactory.getLogger("req");
    private static final Logger devicelog = LoggerFactory.getLogger("device");


    private AtomicInteger IDFASUCCES = new AtomicInteger(0);
    private AtomicInteger IDFAERROR = new AtomicInteger(0);


    public static long BID_WEIGHT = 4;
    public static long BID_WEIGHT_US = 20;
    private static long KAFKA_LOG_WEIGHT = 5;

    private static float premium = 0.01f;


    @Autowired
    private IpMonitor ipMonitor;

    public static Set<String> APP_GEO = Sets.newHashSet("BRA", "DEU", "ESP", "FRA", "GBR", "IDN", "IND", "ITA", "JPN", "KOR", "MEX", "PHL", "SAU", "THA", "TWN", "USA", "VNM");

    @Value("${landingurl.expire.days}")
    private int landurlExpireDays = 1;
    @Value("${bid.budgetrisk.rate}")
    private float bidBudgetRiskRate = 0.9f;

    @Value("${bidgeos}")
    private String bidgeos = null;

    @Value("${rtbname}")
    private String rtbname;
    /**
     * 非线程安全的变量 使用时候需要clone
     */
    @Value("${imprurl}")
    private String impurlTpl;
    @Value("${winurl}")
    private String winurlTpl;
    @Value("${clickurl}")
    private String clickurlTpl;
    @Value("${lurl}")
    private String lurlTpl;

    @Value("${trackingurl}")
    private String trackingUrl;

    @Value("${urlsuffix}")
    private String urlSuffix;
    //@Autowired
    private KafkaBiddingLogger kafkaBiddingLogger;


    @Autowired
    private RestTemplate restTemplate;
    Set<String> rts = Sets.newHashSet("MY1",
            "PH1",
            "VN1",
            "PH2",
            "VN2",
            "TH1",
            "TH2");


    Random random = new Random();

    public List<JSONObject> matchCampaigns(String channel, OpenRTB23BidRequest req) throws Exception {


        String appid = "";
        String siteId = "";
        String publisher = "";
        String appBundle = "";
        String appDomain = "";
        String siteDomain = "";
        List<String> inventoryType = new LinkedList<>();
        String deviceModel = "";
        String[] iabCats = {};
        String[] badv = {};
        String[] bapp = {};

        String[] bIabCats = {};
        String country = "";
        String idfa = "";
        String idfv = "";
        String oaid = "";
        String os = "";
        String ip = "";
        String osv = "";
        String city = "";
        String carrier = "";
        String storeurl = "";
        int connecttype = -1;
        int deviceType = -1;
        List<String> cidsBySchedule;
        List<JSONObject> campaigns = new LinkedList<>();


        inventoryType = new ArrayList<>(2);
        bIabCats = req.getBcat();
        badv = req.getBadv();
        if (req.getApp() != null) {
            inventoryType.add(InventoryTypeE.APP.v);

            if (req.getApp() != null) {
                if (req.getApp().getPublisher() != null) {
                    publisher = req.getApp().getPublisher().getId();
                }
                appid = req.getApp().getId();
                appBundle = req.getApp().getBundle();
                appDomain = req.getApp().getDomain();
                iabCats = req.getApp().getCat();
                if (StringUtils.isNotBlank(req.getApp().getStoreurl())) {

                    storeurl = req.getApp().getStoreurl();
                }
            }
        }
        if (req.getSite() != null) {
            inventoryType.add(InventoryTypeE.WEB.v);
            siteId = req.getSite().getId();
            siteDomain = req.getSite().getDomain();
        }
        country = RtbUtil.get23Country(req);

        if (req.getDevice() != null) {
            ip = req.getDevice().getIp();
            idfa = RtbUtil.get23Ifa(req);
            idfv = RtbUtil.getAlgorixIfv(req);
            oaid = RtbUtil.getAlgorixOaid(req);
            req.getDevice().setIdfv(idfv == null ? "" : idfv);
            req.getDevice().setOaid(oaid == null ? "" : oaid);
            os = RtbUtil.get23OS(req);
            osv = req.getDevice().getOsv() == null ? "" : req.getDevice().getOsv();
            deviceModel = req.getDevice().getModel() == null ? "" : req.getDevice().getModel();
            carrier = req.getDevice().getCarrier() == null ? "" : req.getDevice().getCarrier();
            if (StringUtils.isBlank(carrier)) {
                if (req.getExt() != null && req.getExt().getCarriername() != null) {
                    carrier = req.getExt().getCarriername();
                }
            }
            connecttype = req.getDevice().getConnectiontype();
            if (req.getDevice().getGeo() != null) {
                city = req.getDevice().getGeo().getCity();
            }
            deviceType = req.getDevice().getDevicetype();
            if (StringUtils.isBlank(ip)) {
                ip = req.getDevice().getIpv6();
            }
            if (StringUtils.isBlank(ip)) {
                ip = "";
            }
        }
        String mccmnc = req.getDevice().getMccmnc();
        if (StringUtils.isBlank(ip)
                || StringUtils.isBlank(country)
                || (StringUtils.isBlank(idfa) && StringUtils.isBlank(idfv) && StringUtils.isBlank(oaid))
                || StringUtils.isBlank(appBundle)) {
            /**
             * 如果 这些信息不存在 不Bid
             */
            return null;
        }
        if (idfa.indexOf("000") >= 0) {
            return null;
        }

        if (idFilter.filter(idfa, idfv, oaid)) {
            return null;
        }


        try {
            DeviceInfo deviceInfo = new DeviceInfo();
            deviceInfo.setAppid(appBundle);
            deviceInfo.setDevid(idfa);
            deviceInfo.setGeo(GeoMap.word3Map.get(country));
            deviceInfo.setUa(req.getDevice().getUa());
            deviceInfo.setModel(req.getDevice().getModel());
            deviceInfo.setMake(req.getDevice().getMake());
            deviceInfo.setPub(publisher);
            deviceInfo.setSsp(ExchangesE.getCode(channel));
            deviceInfo.setOs(os);

            printReqLog(channel, ip, appBundle, os, country, req, idfa, iabCats, storeurl, publisher);
            /**
             * 如果出现不确定问题 先暂停bid
             * 比如拉取活动出错
             */
            if (RtbStatus.BID_LOCK) {
                return null;
            }
            if (RtbStatus.BID_LOCK_BY_BUDGET_ERROR) {
                return null;
            }
//            if (RtbStatus.BID_LOCK_BY_CLICKS_ERROR) {
//                return null;
//            }
      /*      if (bidgeos.indexOf(country) < 0) {
                return null;
            }*/

            /**
             * 降频
             * 减少参与bid
             */
            if (req.getImp() == null || req.getImp().length == 0) {
                return null;
            }

            DspTrackLog dspTrackLog = new DspTrackLog();

            dspTrackLog.setIp(ip);
            dspTrackLog.setReqid(req.getId());
            dspTrackLog.setAppbundle(appBundle);
            if (StringUtils.isNotBlank(appid)) {
                dspTrackLog.setAppid(appid);
            } else {
                /**
                 * 如果不存在appid 那么就用web id 代替 带上特定的前缀 web- 表示web
                 */
                dspTrackLog.setAppbundle(InventoryTypeE.WEB.key.concat(AppConstant.URL_SEPARATOR).concat(siteId));
            }

            dspTrackLog.setCarrier(carrier);
            dspTrackLog.setChannel(channel);
            dspTrackLog.setCity(city);
            dspTrackLog.setDevid(idfa);
            dspTrackLog.setDevmodel(deviceModel);
            if (StringUtils.isNotBlank(appDomain)) {

                dspTrackLog.setDomain(appDomain);
            } else {
                /**
                 * appdomain不存在 就用websitedomain 带上特定的前缀 web- 表示web
                 */
                dspTrackLog.setDomain(InventoryTypeE.WEB.key.concat(AppConstant.URL_SEPARATOR).concat(siteDomain));
            }
            dspTrackLog.setGeo(country);
            dspTrackLog.setOs(os);
            dspTrackLog.setOsv(osv);
            dspTrackLog.setPubid(publisher);
            dspTrackLog.setSiteid(siteId);
            dspTrackLog.setStmp(LocalDateTime.now().format(DateTimeFormatter.ofPattern(Patten.DATETIME)));
            dspTrackLog.setConnecttype(connecttype);
            dspTrackLog.setDevicetype(deviceType);
            dspTrackLog.setMccmnc(mccmnc);

            req.setDspTrackLog(dspTrackLog);

            /**
             * 黑名单过滤
             */
            if (isBlockList(req)) {
                return null;
            } else {

                // app请求次数 记录
                LongAdder al = SimpleBidData.APP_REQUEST.get(appBundle);

                if (al == null) {
                    SimpleBidData.APP_REQUEST.put(appBundle, new LongAdder());
                } else {
                    al.increment();
                }
            }


            /**
             * Ip请求次数限制
             */
       /*     if (ipMonitor.existisBlockIp(ip)) {

                return null;
            }
*/

            /**
             * 投放时段定向
             */
            LocalDateTime reqTime = LocalDateTime.now(CTZ.of(country));
            /**
             * 请求信息定向
             */
            cidsBySchedule = queryBySche(reqTime.getDayOfWeek().getValue(), reqTime.getHour());
            if (CollectionUtils.isEmpty(cidsBySchedule)) {
                return null;
            }


            try {

                BooleanQuery.Builder builder = new BooleanQuery.Builder();


                /*
                如果存在IDFA 就根据IDFA获取 IDFA 的 展现 定向 以及安装的APP信息 用来检索活动
                */
                /*if (StringUtils.isNotBlank(idfa)) {

                    try {
                        Map userFace = redisIdfaTemplate.opsForHash().entries(idfa);
                        Set<String> keys = userFace.keySet();
                        if (keys != null) {
                            List<BytesRef> idfaConvAppList = keys.stream()
                                    .filter(n -> n.startsWith(AppConstant.CONV_PREFIX))
                                    .map(app -> new BytesRef(app.replace(AppConstant.CONV_PREFIX, "")))
                                    .collect(Collectors.toList());
                            if (!CollectionUtils.isEmpty(idfaConvAppList)) {

                                builder.add(new TermInSetQuery("advappbundle", idfaConvAppList), BooleanClause.Occur.MUST_NOT);
                            }

                            List<String> idfaTargetCids = keys.stream()
                                    .filter(n -> n.startsWith(AppConstant.TARGET_PREFIX))
                                    .map(cid -> cid.replace(AppConstant.TARGET_PREFIX, ""))
                                    .collect(Collectors.toList());
                            if (!CollectionUtils.isEmpty(idfaTargetCids)) {

                                logger.info("idfatarget:{}:{}", idfa, idfaTargetCids);
                                cidsBySchedule.retainAll(idfaTargetCids);
                            }


                        }
                        IDFASUCCES.incrementAndGet();
                    } catch (Exception e) {
                        int errors = IDFAERROR.incrementAndGet();

                        logger.error("IDFATIMEOUT".concat(String.valueOf(errors)).concat(AppConstant.LOG_SEPARATOR).concat(String.valueOf(IDFASUCCES.get())), e);
                    }


                }*/

                builder.add(new TermInSetQuery("id", cidsBySchedule.stream().map(n -> new BytesRef(n)).collect(Collectors.toList())), BooleanClause.Occur.MUST);
                builder.add(new TermInSetQuery("id", SimpleData.BUDGET_DAILY_FULL_CAMPAIGN.stream().map(n -> new BytesRef(n)).collect(Collectors.toList())), BooleanClause.Occur.MUST_NOT);
                List<BytesRef> ins = inventoryType.stream().map(n -> new BytesRef(n)).collect(Collectors.toList());
                builder.add(new TermInSetQuery("inventorytype", ins), BooleanClause.Occur.MUST);
                builder.add(new TermQuery(new Term("targetingos", os)), BooleanClause.Occur.MUST);

                /**
                 * 操作系统版本控制
                 */
                String osvnew = null;
                if (!StringUtils.isBlank(osv) && !"..0".equalsIgnoreCase(osv)) {
                    String[] osva = osv.split("\\.");
                    if (osva.length == 1) {
                        osvnew = osva[0];
                    }
                    if (osva.length >= 2) {
                        osvnew = new StringBuffer().append(osva[0]).append(".").append(osva[1]).toString();
                    }
                }
                if (OsE.Android.v.equalsIgnoreCase(os) && StringUtils.isNotBlank(osvnew)) {
                    try {
                        float osvf = Float.parseFloat(osvnew);
                        builder.add(FloatPoint.newRangeQuery("andoridminiv", 0f, osvf), BooleanClause.Occur.MUST);
                        builder.add(FloatPoint.newRangeQuery("andoridmaxv", osvf, 111f), BooleanClause.Occur.MUST);
                    } catch (NumberFormatException e) {
                        //errorlogger.error(osv);
                        //errorlogger.error(osvnew);
                    }
                }
                if (OsE.iOS.v.equalsIgnoreCase(os) && StringUtils.isNotBlank(osvnew)) {
                    try {
                        float osvf = Float.parseFloat(osvnew);
                        builder.add(FloatPoint.newRangeQuery("iosminiv", 0f, osvf), BooleanClause.Occur.MUST);
                        builder.add(FloatPoint.newRangeQuery("iosmaxv", osvf, 111f), BooleanClause.Occur.MUST);
                    } catch (NumberFormatException e) {
                        //errorlogger.error(osv);
                        //errorlogger.error(osvnew);

                    }
                }


                builder.add(new TermQuery(new Term("exchanges", channel)), BooleanClause.Occur.MUST);
                builder.add(new TermQuery(new Term("state", String.valueOf(StateE.VALID.code))), BooleanClause.Occur.MUST);
                builder.add(new TermQuery(new Term("deleteflag", String.valueOf(DelFlagE.NO.code))), BooleanClause.Occur.MUST);
                /**
                 * 设备ID为空 查询活动没有配置只包含设备编号的
                 */
                if (StringUtils.isBlank(idfa)) {
                    builder.add(new TermQuery(new Term("frequencytype", FrequencyTypeE.CONTAINSIDFA.key)), BooleanClause.Occur.MUST_NOT);
                }

                /**
                 *  bcat 排除block cat
                 */
                if (bIabCats != null && bIabCats.length > 0) {
                    builder.add(new TermInSetQuery("iabcats", Stream.of(bIabCats).map(n -> new BytesRef(n)).collect(Collectors.toList())), BooleanClause.Occur.MUST_NOT);

                }


                /**
                 *  badv 排除 adv domain
                 */
                if (badv != null && badv.length > 0) {
                    builder.add(new TermInSetQuery("advdomain", Stream.of(badv).map(n -> new BytesRef(n)).collect(Collectors.toList())), BooleanClause.Occur.MUST_NOT);

                }


                /**
                 * 如果请求设备类型为1为过去的RTB协议，代表着2.2之后的 4，5两个类型
                 */
                if (DeviceTypeE.MobilTablet.v.equals(String.valueOf(deviceType))) {
                    builder.add(new TermInSetQuery("devicetype", Stream.of(DeviceTypeE.Phone.v, DeviceTypeE.Tablet.v).map(n -> new BytesRef(n)).collect(Collectors.toList())), BooleanClause.Occur.MUST);
                } else {
                    builder.add(new TermQuery(new Term("devicetype", String.valueOf(deviceType))), BooleanClause.Occur.MUST);
                }
                /**
                 * 如果是3G 或者 4G网络  在lucene里存储的类型都是3
                 * 因为系统存储了
                 * 2 WIFI
                 * 3 CELLULAR
                 */

                if (!(ConnectionType.CONNECTION_UNKNOWN.getValue() == connecttype || ConnectionType.ETHERNET.getValue() == connecttype)) {
                    if (ConnectionType.CELL_2G.getValue() == connecttype || ConnectionType.CELL_3G.getValue() == connecttype
                            || ConnectionType.CELL_4G.getValue() == connecttype || ConnectionType.CELL_5G.getValue() == connecttype) {
                        builder.add(new TermQuery(new Term("connectiontype", "3")), BooleanClause.Occur.MUST);
                    } else {
                        builder.add(new TermQuery(new Term("connectiontype", String.valueOf(connecttype))), BooleanClause.Occur.MUST);
                    }
//                    if (ConnectTypeE.G3.v.equals(String.valueOf(connecttype)) || ConnectTypeE.G4.v.equals(String.valueOf(connecttype))) {
//                        builder.add(new TermQuery(new Term("connectiontype", "3")), BooleanClause.Occur.MUST);
//                    } else if (!ConnectTypeE.Other.v.equals(String.valueOf(connecttype))) {
//                        builder.add(new TermQuery(new Term("connectiontype", String.valueOf(connecttype))), BooleanClause.Occur.MUST);
//                    }
                }


                BidIndex.buildCfgQuery(builder, country, CfgKeyE.TARGETING_COUNTRIES.key);
                BidIndex.buildCfgQuery(builder, appid, CfgKeyE.INVENTORY_APPSITE.key);
                BidIndex.buildCfgQuery(builder, siteId, CfgKeyE.INVENTORY_APPSITE.key);
                BidIndex.buildCfgQuery(builder, publisher, CfgKeyE.INVENTORY_PUBLISHERS.key);
                BidIndex.buildCfgQuery(builder, appBundle, CfgKeyE.INVENTORY_APPBUNDLES.key);
                BidIndex.buildCfgQuery(builder, ip, CfgKeyE.TARGETING_IPRANGES.key);
                BidIndex.buildCfgQuery(builder, appDomain, CfgKeyE.INVENTORY_DOMAINLIST.key);
                BidIndex.buildCfgQuery(builder, siteDomain, CfgKeyE.INVENTORY_DOMAINLIST.key);
                BidIndex.buildCfgQuery(builder, idfa, CfgKeyE.TARGETING_DEVICEID.key);
                BidIndex.buildCfgQuery(builder, carrier, CfgKeyE.TARGETING_CARRIERS.key);
                BidIndex.buildCfgQuery(builder, deviceModel, CfgKeyE.TARGETING_DEVICEMODEL.key);
                if (iabCats != null && iabCats.length > 0) {
                    BidIndex.buildCfgQueryByMutilValue(builder, iabCats, CfgKeyE.INVENTORY_APPIABCATEGORY.key);
                }

                IndexReader readerCam = DirectoryReader.open(BidIndex.CAMPAIGNS_W);
                IndexSearcher searcherCam = new IndexSearcher(readerCam);
                Query query = new ConstantScoreQuery(builder.build()).getQuery();
                TopDocs results = searcherCam.search(query, Integer.MAX_VALUE);

                ScoreDoc[] hits = results.scoreDocs;

                for (ScoreDoc scoreDoc : hits) {
                    Document doc = searcherCam.doc(scoreDoc.doc);
                    campaigns.add(BidIndex.doc2Json(doc));
                }


            } catch (IOException e) {
                errorlogger.error("matchCampaigns".concat(JSONObject.toJSONString(req)), e);
            }


            if (CollectionUtils.isEmpty(campaigns)) {
                return null;
            }


        } catch (Exception e) {
            StringBuffer info = new StringBuffer();
            e.printStackTrace();
            errorlogger.error(info.append("bidargs:").append("reqid:").append(req.getId()).append(" appid:").append(appid).append(" siteId:").append(siteId
            ).append(" publisher:").append(publisher).append(" appBundle:").append(appBundle).append(" appDomain:").append(appDomain).append(" siteDomain:").append(siteDomain
            ).append(" deviceModel:").append(deviceModel).append(" iabCats:").append(iabCats).append(" country:").append(country).append(" idfa:").append(idfa
            ).append(" os:").append(os).append(" osv:").append(osv).append(" connecttype:").append(connecttype).append(" deviceType:").append(deviceType).toString(), e);
            return null;
        }
        return campaigns;
    }


    /**
     * 根据请求展现集合，返回展现和符合展现的活动素材列表
     *
     * @param req
     * @return
     * @throws Exception
     */
    public Map<String, List<Campaign>> matchCreative(String channel, List<Campaign> campaigns, OpenRTB23BidRequest req, List<JSONObject> campaignsS) throws Exception {
        Map<String, List<Campaign>> impCampaigns = Maps.newHashMap();

        for (Imp imp : req.getImp()) {
            /**
             * 目前只支持http
             */
   /*         if (imp.getSecure() == ImpSecureE.SECURE.code) {
                continue;
            }*/

            /**
             * 只参与美元计价的请求 如果 bidfloorcur 为空 默认为 USD
             */
            if (StringUtils.isBlank(imp.getBidfloorcur())) {
                imp.setBidfloorcur(BID_CUR_UNIT);
            }
            if (StringUtils.isNotEmpty(imp.getBidfloorcur()) && !BID_CUR_UNIT.equalsIgnoreCase(imp.getBidfloorcur())) {
                continue;
            }


            List<Campaign> matchCampaigns = new LinkedList<>();
            String country = RtbUtil.get23Country(req);
            if (country.toLowerCase().equals("chn")) {
                List<Campaign> cc = queryCHNCreative(channel, campaigns, imp, req);
                if (!CollectionUtils.isEmpty(cc)) {
                    matchCampaigns.addAll(cc);
                }
            } else {
                List<Campaign> cc = queryCampaignAndCreative(channel, campaignsS, imp, req);
                if (!CollectionUtils.isEmpty(cc)) {
                    matchCampaigns.addAll(cc);
                }
            }

            if (matchCampaigns.size() > 0) {
                impCampaigns.put(imp.getId(), matchCampaigns);
            }

        }


        return impCampaigns;
    }


    public Map<String, List<Campaign>> targeting(OpenRTB23BidRequest req, Map<String, List<Campaign>> impMatchCampaigns) throws Exception {
        Map<String, List<Campaign>> targeting = Maps.newHashMap();
        LocalDateTime now = LocalDateTime.now();
        String day = now.format(DateTimeFormatter.ofPattern(Patten.DATE));
        impMatchCampaigns
                .forEach((impid, campaigns) -> {

                    List newCampaigns = campaigns.stream().filter(campaign -> true).collect(Collectors.toList());


                    /**
                     * 控制频次 bugflag
                     */

                    if (!CollectionUtils.isEmpty(newCampaigns)) {
                        targeting.put(impid, newCampaigns);
                    }
                });


        return targeting;
    }

    /**
     * @param hits
     * @param searcher
     * @param campaign
     * @param creativeList
     * @param impAdPos     素材IMP广告位
     * @throws IOException
     */
    private void putCreative(ScoreDoc[] hits, IndexSearcher searcher, Campaign campaign, List<Creative> creativeList, int impAdPos) throws IOException {
        for (ScoreDoc scoreDoc : hits) {
            Document doc = searcher.doc(scoreDoc.doc);
            try {
                Creative creative = JSONObject.toJavaObject(BidIndex.doc2Json(doc), Creative.class);
                if (campaign != null && creative != null) {
                    /*
                    包装素材以及IMP对象信息
                     */
                    creative.setImpadpos(impAdPos);

                    creativeList.add(creative);
                }
            } catch (Exception e) {
                errorlogger.error(BidIndex.doc2Json(doc).toJSONString(), e);

            }
        }
    }


    private void putNativeCreative(ScoreDoc[] hits, IndexSearcher searcher, Campaign campaign, List<CreativeNative> creativeList) throws IOException {
        for (ScoreDoc scoreDoc : hits) {
            Document doc = searcher.doc(scoreDoc.doc);
            CreativeNative creative = JSONObject.toJavaObject(BidIndex.doc2Json(doc), CreativeNative.class);
            if (campaign != null && creative != null) {

                creativeList.add(creative);
            }
        }
    }

    private List<Campaign> queryCHNCreative(String channel, List<Campaign> campaigns, Imp imp, OpenRTB23BidRequest bidRequest) {

        if (channel.equalsIgnoreCase(ExchangesE.ALGORIX.key)) {
            JSONObject ext = (JSONObject) imp.getExt();
//            广告位类型 1:banner, 2: interstitial, 3: full screen , 4: native, 5: video
            Integer tagtype = (Integer) ext.get("tagtype");
            if (tagtype == null || tagtype == 0) {
                return null;
            }
            Integer width = (Integer) ext.get("w");
            Integer height = (Integer) ext.get("h");
            if (width == null || width == 0 || height == null || height == 0) {
                return null;
            }
            switch (tagtype) {
                case 1:
                case 2:
                case 3:
                    return doQueryCHNCreative(channel, campaigns, imp, bidRequest, width, height, tagtype);
                case 4:
                    // native
                    return doQueryCHNNative(channel, campaigns, imp, bidRequest, width, height, tagtype);
                case 5:
                    // video
                    return doQueryCHNVideo(channel, campaigns, imp, bidRequest, width, height, tagtype);
            }

        }
        return null;
    }

    private List<Campaign> doQueryCHNCreative(String channel, List<Campaign> campaigns, Imp imp, OpenRTB23BidRequest bidRequest, Integer width, Integer height, Integer tagType) {
        List<Campaign> impMatchCampaigns = new LinkedList<>();

        campaigns.forEach(c -> {
            Campaign campaign = c;

//            if (campaign.getBuyingprice() > imp.getBidfloor()) {
            Creative creative = sourceManager.getImg(campaign.getId().intValue(), width, height);
//                Creative creative = bidIndex.getCreative(campaign.getId().intValue(), width, height);
            if (creative == null) {
                return;
            }
            campaign.setCreative(creative);
            campaign.setCreativeType(tagType);
            impMatchCampaigns.add(campaign);
//            }
        });

        return impMatchCampaigns;
    }

    private List<Campaign> doQueryCHNNative(String channel, List<Campaign> campaigns, Imp imp, OpenRTB23BidRequest bidRequest, Integer width, Integer height, Integer tagType) {
        List<Campaign> impMatchCampaigns = new LinkedList<>();


        campaigns.forEach(c -> {
            Campaign campaign = c;

//            if (campaign.getBuyingprice() > imp.getBidfloor()) {
            NativeAdWrapper nativeAd = sourceManager.getNative(campaign.getId().intValue(), width, height);
            if (nativeAd == null) {
                return;
            }
            campaign.setNativeAdWrapper(nativeAd);
            campaign.setCreativeType(tagType);
            impMatchCampaigns.add(campaign);
//            }
        });

        return impMatchCampaigns;
    }

    private List<Campaign> doQueryCHNVideo(String channel, List<Campaign> campaigns, Imp imp, OpenRTB23BidRequest bidRequest, Integer width, Integer height, Integer tagType) {
        List<Campaign> impMatchCampaigns = new LinkedList<>();


        campaigns.forEach(c -> {
            Campaign campaign = c;

//            if (campaign.getBuyingprice() > imp.getBidfloor()) {
            Creative creative = sourceManager.getVideo(campaign.getId().intValue(), width, height);
            if (creative == null) {
                return;
            }
            campaign.setCreative(creative);
            campaign.setCreativeType(tagType);
            impMatchCampaigns.add(campaign);
//            }
        });

        return impMatchCampaigns;
    }


    private List<Campaign> queryCampaignAndCreative(String channel, List<JSONObject> campaigns, Imp imp, OpenRTB23BidRequest bidRequest) {
        List<Campaign> impMatchCampaigns = new LinkedList<>();
        try {
            campaigns.forEach(n -> {
                Campaign campaign = JSONObject.toJavaObject(n, Campaign.class);
                /**
                 * 根据每个活动和素材的关系 以及 素材尺寸 ，去素材的索引里检索素材
                 * 包装秤一个单次请求可用的活动和素材对应关系
                 */
                List<Creative> creativeList = Lists.newLinkedList();
                String creatives = n.getString("CREATIVES");

                if (campaign.getBuyingprice() > imp.getBidfloor()) {
                    /**
                     * 当imp 是视频时候 ，如果 linearity 为 NonLinear 那么其实返回的XML 包含的素材可以使图片 以及js 以及视频等 这里后续要注意
                     */

                    Banner banner = imp.getBanner();
                    Video video = imp.getVideo();
                    Native nativead = imp.getNativead();
                    //目前只bid banner 富媒体
                    boolean dobid = false;
                    if (banner != null && banner.getApi() != null && banner.getApi().length > 0) {
                        for (int api : banner.getApi()) {
                            if (api == 3 || api == 5) {
                                dobid = true;
                            }
                        }
                    }
                    if (!dobid) {
                        return;
                    }
                    //

                    if (nativead == null) {
                        if (banner != null) {
                            int w = banner.getW();
                            int h = banner.getH();

                            if (w <= 0 || h <= 0) {
                                if (banner.getFormat() != null && banner.getFormat().length > 0) {
                                    w = banner.getFormat()[0].getW();
                                    h = banner.getFormat()[0].getH();
                                }
                            }
                            String[] mimes = banner.getMimes();
                            BooleanQuery.Builder builder = new BooleanQuery.Builder();
                            builder.add(new TermQuery(new Term("size", w + "x" + h)), BooleanClause.Occur.MUST);
                            if (!StringUtils.isBlank(creatives)) {
                                String[] creativeIds = creatives.split(",");
                                if (creativeIds.length > 0) {
                                    try {
                                        List<String> ids = Arrays.asList(creativeIds);
                                        builder.add(new TermQuery(new Term("state", String.valueOf(StateE.VALID.code))), BooleanClause.Occur.MUST);
                                        builder.add(new TermQuery(new Term("deleteflag", String.valueOf(DelFlagE.NO.code))), BooleanClause.Occur.MUST);
                                        builder.add(new TermInSetQuery("id", ids.stream().map(id -> new BytesRef(id)).collect(Collectors.toList())), BooleanClause.Occur.MUST);
                                        List<String> mimeslist = null;
                                        if (channel.equalsIgnoreCase(ExchangesE.ALGORIX.key)) {
                                            /*
                                            如果是 mobfox里的区别富媒体是在 ext的对象里包含mraid的key 
                                             */
                                            if (imp.getExt() != null) {
                                                try {
                                                    String exts = JSONObject.toJSONString(imp.getExt());
                                                    JSONObject ext = JSONObject.parseObject(exts);

                                                    if (ext.containsKey("mraid")) {
                                                        if (mimes == null) {
                                                            mimeslist = Lists.newLinkedList();
                                                            mimeslist.add("text/javascript");
                                                            mimeslist.add("application/javascript");
                                                        } else {
                                                            mimeslist = Arrays.asList(mimes);
                                                            mimeslist.add("text/javascript");
                                                            mimeslist.add("application/javascript");
                                                        }

                                                    }
                                                } catch (Exception e) {
                                                    e.printStackTrace();
                                                }
                                            }


                                        }


                                        if (mimeslist == null) {
                                            mimeslist = Lists.newLinkedList();
                                        }
                                        if (mimes != null) {
                                            mimeslist.addAll(Arrays.asList(mimes));
                                        }
                                        if (mimes != null && mimeslist != null) {

                                            if (mimeslist.contains("image/jpeg")) {
                                                mimeslist.add("image/jpg");
                                            }
                                            builder.add(new TermInSetQuery("mime", mimeslist.stream().map(mime -> new BytesRef(mime)).collect(Collectors.toList())), BooleanClause.Occur.MUST);
                                        }

                                        builder.add(new TermQuery(new Term("type", String.valueOf(CreativeTypeE.BANNER.code))), BooleanClause.Occur.MUST);

                                        IndexReader reader = DirectoryReader.open(BidIndex.CREATIVES_W);
                                        IndexSearcher searcher = new IndexSearcher(reader);
                                        Query query = new ConstantScoreQuery(builder.build()).getQuery();
                                        TopDocs results = searcher.search(query, 10);
                                        ScoreDoc[] hits = results.scoreDocs;
                                        putCreative(hits, searcher, campaign, creativeList, banner.getPos());
                                        if (mimeslist != null) {
                                            /**
                                             * 如果素材请求类型包含javascript 说明支持富媒体
                                             * 那么可以返回将banner 上升成富媒体形式
                                             */

                                            if (mimeslist.contains("text/javascript") || mimeslist.contains("application/javascript")) {
                                                campaign.setSecondCreativeType(CreativeTypeE.HTML.code);
                                            }
                                        }


                                    } catch (IOException e) {
                                        e.printStackTrace();
                                    }

                                }

                            }

                        } else if (video != null && (video.getLinearity() == VideoLinearityE.LINEAR.code || video.getLinearity() == 0)) {
                            /**
                             * 暂时支持VAST2 以及 VAST2 W
                             */
                            boolean flag = false;
                            if (video.getProtocols() == null) {
                                return;
                            }
                            /**
                             * vast2 判断
                             */
                            for (int p : video.getProtocols()) {
                                if (p == VideoProtocolsE.VAST2.code) {
                                    flag = true;
                                    break;
                                }
                            }
                            if (!flag) {
                                return;
                            }

                            int w = video.getW();
                            Double minw = w * 0.9;
                            Double maxw = w * 1.1;
                            int h = video.getH();

                            Double minh = h * 0.9;
                            Double maxh = h * 1.1;
                            /**
                             * 视频的播放时长
                             */
                            int dmin = video.getMinduration();
                            int dmax = video.getMaxduration();
                            /**
                             * 视频的 字节 Kb 转 byte
                             */
                            int bsizemin = video.getMinbitrate() * 1024;
                            int bsizemax = video.getMaxbitrate() * 1024;


                            String[] mimes = video.getMimes();
                            BooleanQuery.Builder builder = new BooleanQuery.Builder();
                            //builder.add(new TermQuery(new Term("size", w + "x" + h)), BooleanClause.Occur.MUST);
                            if (!StringUtils.isBlank(creatives)) {
                                String[] creativeIds = creatives.split(",");
                                if (creativeIds.length > 0) {
                                    try {
                                        List<String> ids = Arrays.asList(creativeIds);
                                        builder.add(new TermQuery(new Term("state", String.valueOf(StateE.VALID.code))), BooleanClause.Occur.MUST);
                                        builder.add(new TermQuery(new Term("deleteflag", String.valueOf(DelFlagE.NO.code))), BooleanClause.Occur.MUST);
                                        builder.add(new TermInSetQuery("id", ids.stream().map(id -> new BytesRef(id)).collect(Collectors.toList())), BooleanClause.Occur.MUST);
                                        builder.add(IntPoint.newRangeQuery("w", minw.intValue(), maxw.intValue()), BooleanClause.Occur.MUST);
                                        builder.add(IntPoint.newRangeQuery("h", minh.intValue(), maxh.intValue()), BooleanClause.Occur.MUST);
                                        if (mimes != null) {

                                            builder.add(new TermInSetQuery("mime", Arrays.asList(mimes).stream().map(mime -> new BytesRef(mime)).collect(Collectors.toList())), BooleanClause.Occur.MUST);
                                        }
                                        if (dmax > 0) {

                                            builder.add(IntPoint.newRangeQuery("videoduration", dmin, dmax), BooleanClause.Occur.MUST);
                                        }

                                        if (bsizemax > 0) {

                                            builder.add(LongPoint.newRangeQuery("bsize", bsizemin, bsizemax), BooleanClause.Occur.MUST);
                                        }
                                    /*
                                    REWARDED
                                     */
                                        builder.add(new TermInSetQuery("type", Arrays.asList(String.valueOf(CreativeTypeE.VIDEO.code), String.valueOf(CreativeTypeE.REWARDEDVIDEO.code)).stream().map(ts -> new BytesRef(ts)).collect(Collectors.toList())), BooleanClause.Occur.MUST);

                                        IndexReader reader = DirectoryReader.open(BidIndex.CREATIVES_W);
                                        IndexSearcher searcher = new IndexSearcher(reader);
                                        Query query = new ConstantScoreQuery(builder.build()).getQuery();
                                        TopDocs results = searcher.search(query, 10);
                                        ScoreDoc[] hits = results.scoreDocs;
                                        putCreative(hits, searcher, campaign, creativeList, video.getPos());


                                    } catch (IOException e) {
                                        e.printStackTrace();
                                    }

                                }

                            }
                        }

                        if (creativeList.size() > 0) {
                            Creative creative = electCreative(creativeList, bidRequest);
                            campaign.setCreative(creative);
                            campaign.setCreativeType(creative.getType());
                            impMatchCampaigns.add(campaign);
                        }
                    } else {
                        /**
                         * 检索并且筛选native素材 目前就是随机一个native
                         */
                        List<CreativeNative> nativeslist = Lists.newLinkedList();
                        String[] creativeIds = creatives.split(",");
                        if (creativeIds.length > 0) {
                            IndexSearcher searcher = null;
                            try {
                                List<String> ids = Arrays.asList(creativeIds);
                                BooleanQuery.Builder builder = new BooleanQuery.Builder();
                                builder.add(new TermQuery(new Term("state", String.valueOf(StateE.VALID.code))), BooleanClause.Occur.MUST);
                                builder.add(new TermQuery(new Term("deleteflag", String.valueOf(DelFlagE.NO.code))), BooleanClause.Occur.MUST);
                                builder.add(new TermInSetQuery("id", ids.stream().map(id -> new BytesRef(id)).collect(Collectors.toList())), BooleanClause.Occur.MUST);

                                IndexReader reader = DirectoryReader.open(BidIndex.CREATIVES_NATIVE_W);
                                searcher = new IndexSearcher(reader);
                                Query query = new ConstantScoreQuery(builder.build()).getQuery();
                                TopDocs results = searcher.search(query, 100);
                                ScoreDoc[] hits = results.scoreDocs;
                                putNativeCreative(hits, searcher, campaign, nativeslist);


                            } catch (Exception e) {
                                e.printStackTrace();
                            }
                            if (!CollectionUtils.isEmpty(nativeslist)) {
                                CreativeNative creative = electNativeCreative(nativeslist, bidRequest);
                                campaign.setCreativeNative(creative);
                                campaign.setCreativeType(CreativeTypeE.NATIVE.code);
                                impMatchCampaigns.add(campaign);
                            }

                        }

                    }

                }
            });


        } catch (Exception e) {
            errorlogger.error("queryCampaignAndCreative", e);
        }
        return impMatchCampaigns;

    }

    private List<String> queryBySche(int d, int h) {
        List<String> cids = new LinkedList<>();
        try {
            BooleanQuery.Builder builderSche = new BooleanQuery.Builder();
            builderSche.add(new TermQuery(new Term("d", String.valueOf(d))), BooleanClause.Occur.MUST);
            builderSche.add(IntPoint.newRangeQuery("st", 0, h), BooleanClause.Occur.MUST);
            builderSche.add(IntPoint.newRangeQuery("et", h, 23), BooleanClause.Occur.MUST);

            IndexReader readerSche = DirectoryReader.open(BidIndex.CAMPAIGNS_SCHE_W);
            IndexSearcher searcherSche = new IndexSearcher(readerSche);
            Query queryChe = new ConstantScoreQuery(builderSche.build()).getQuery();
            TopDocs resultsSche = searcherSche.search(queryChe, Integer.MAX_VALUE);

            ScoreDoc[] hitsSche = resultsSche.scoreDocs;
            for (ScoreDoc scoreDoc : hitsSche) {
                Document doc = searcherSche.doc(scoreDoc.doc);
                cids.add(doc.get("cid"));
            }
        } catch (IOException e) {
            errorlogger.error("queryBySche", e);
        }
        return cids;

    }


    public void setAdm(String channel, Campaign winCampaign, OpenRTB23BidRequest bidRequest, Bid bid, Imp
            imp, String clickUrl, String impUrl, String landurl, String impUrl2) {


        Creative creative = winCampaign.getCreative();
        if (ExchangesE.SMAATO.key.equalsIgnoreCase(channel)) {
            if (CreativeTypeE.BANNER.code == creative.getType()) {
                /*    if (CreativeTypeE.HTML.code == winCampaign.getSecondCreativeType()) {
                 *//**
                 * 如果存在banner图片，且可以返回富媒体素材，那么将图片自动转为富媒体简单模板代码，可以追踪点击事件坐标
                 * 之后设置bidlog的素材类型为富媒体 而不是默认的banner
                 *//*
                    String richBody = AdmTemplate.createSmaatoSimpleMraidBody(creative.getUrl(), creative.getW(), creative.getH(), impUrl, clickUrl);
                    bid.setAdm(SmaatoAdmTemplate.createSmaatoRichMediaTpl(winCampaign, richBody, impUrl, clickUrl));
                    bidRequest.getDspTrackLog().setCtype(String.valueOf(CreativeTypeE.HTML.code));
                } else {

                    bid.setAdm(SmaatoAdmTemplate.createSmaatoImgTpl(imp, winCampaign, clickUrl, impUrl));
                    bidRequest.getDspTrackLog().setCtype(String.valueOf(CreativeTypeE.BANNER.code));

                }*/
                bid.setAdm(SmaatoAdmTemplate.createSmaatoImgTpl(0, rtbname, imp, winCampaign, clickUrl, impUrl, impUrl2, bidRequest));
                bidRequest.getDspTrackLog().setCtype(String.valueOf(CreativeTypeE.BANNER.code));

            } else if (CreativeTypeE.HTML.code == creative.getType()) {
                String script = new String(SimpleData.RICH_MEDIA.get(creative.getId()));
                script = script.replaceAll("\\{CLICKURL}", clickUrl).replaceAll("\\{IMPURL}", impUrl);
                bid.setAdm(SmaatoAdmTemplate.createSmaatoRichMediaTpl(winCampaign, script, impUrl, clickUrl, impUrl2));
                bidRequest.getDspTrackLog().setCtype(String.valueOf(CreativeTypeE.HTML.code));


            } else if (CreativeTypeE.VIDEO.code == creative.getType() || CreativeTypeE.REWARDEDVIDEO.code == creative.getType()) {
                // 只有linearity =1 时候 认为返回素材是video
                bid.setAdm(VastTemplate.vast2LinearTpl(bid, winCampaign, impUrl, clickUrl, imp, impUrl2));
                bidRequest.getDspTrackLog().setCtype(String.valueOf(CreativeTypeE.VIDEO.code));

            }
        } else {
            if (CreativeTypeE.BANNER.code == creative.getType()) {

        /*        if (CreativeTypeE.HTML.code == winCampaign.getSecondCreativeType()) {
                    String richBody = AdmTemplate.createSimpleMraidMsg(creative.getUrl(), creative.getW(), creative.getH(), impUrl, clickUrl);
                    bid.setAdm(richBody);
                    bidRequest.getDspTrackLog().setCtype(String.valueOf(CreativeTypeE.HTML.code));
                } else {

                    bid.setAdm(AdmTemplate.createMsg(imp, clickUrl, creative.getUrl(), impUrl, creative.getW().toString(), creative.getH().toString()));
                    bidRequest.getDspTrackLog().setCtype(String.valueOf(CreativeTypeE.BANNER.code));

                }*/
                bid.setAdm(AdmTemplate.createMsg(0, channel, winCampaign.getId().toString(), imp, clickUrl, creative.getUrl(), impUrl, creative.getW().toString(), creative.getH().toString(), impUrl2, bidRequest));
                bidRequest.getDspTrackLog().setCtype(String.valueOf(CreativeTypeE.BANNER.code));

            } else if (CreativeTypeE.HTML.code == creative.getType()) {
                bid.setAdm(AdmTemplate.createmraidMsg(winCampaign, new String(SimpleData.RICH_MEDIA.get(creative.getId())), impUrl, clickUrl, impUrl2));
                bidRequest.getDspTrackLog().setCtype(String.valueOf(CreativeTypeE.HTML.code));


            } else if (CreativeTypeE.VIDEO.code == creative.getType() || CreativeTypeE.REWARDEDVIDEO.code == creative.getType()) {
                // 只有linearity =1 时候 认为返回素材是video
                bid.setAdm(VastTemplate.vast2LinearTpl(bid, winCampaign, impUrl, clickUrl, imp, impUrl2));
                bidRequest.getDspTrackLog().setCtype(String.valueOf(CreativeTypeE.VIDEO.code));
            }

        }
        if (ExchangesE.ALGORIX.key.equalsIgnoreCase(channel)) {
            if (winCampaign.getCreativeType() != null && (CreativeTypeE.REWARDEDVIDEO.code == winCampaign.getCreativeType())) {
                JSONObject ext = new JSONObject();
                ext.put("videotype", "rewarded");
                bid.setExt(ext);
            }
        }


    }

    public static void main(String[] args) {
        String res = "{\"native\":{\"ver\":\"1.1\",\"layout\":6,\"adunit\":4,\"assets\":[{\"id\":1,\"img\":{\"hmin\":80,\"type\":1,\"wmin\":80},\"required\":1},{\"id\":2,\"img\":{\"hmin\":627,\"type\":3,\"wmin\":1200},\"required\":1},{\"id\":3,\"title\":{\"len\":25},\"required\":1},{\"id\":4,\"data\":{\"len\":90,\"type\":2},\"required\":1},{\"id\":5,\"data\":{\"type\":3},\"required\":0},{\"id\":6,\"data\":{\"len\":20,\"type\":12},\"required\":0},{\"id\":7,\"data\":{\"len\":25,\"type\":1},\"required\":0}],\"context\":2,\"plcmttype\":1}}";
        JSONObject nativej = JSONObject.parseObject(res);
        Request nativeRequest = null;
        if (nativej.containsKey("native")) {
            nativeRequest = JSONObject.toJavaObject(nativej.getJSONObject("native"), Request.class);

        } else {
            nativeRequest = JSONObject.parseObject(res, Request.class);

        }
        System.out.println(1);

    }

    public void setNativeAdm(String channel, Campaign winCampaign, OpenRTB23BidRequest bidRequest, Bid bid, Imp
            imp, String clickUrl, String impUrl, String landurl, String impUrl2) {

        if (!StringUtils.isEmpty(impUrl2)) {
            impUrl = impUrl2;
        }
        Native nativead = imp.getNativead();


        JSONObject nativej = JSONObject.parseObject(nativead.getRequest());
        Request nativeRequest = null;
        if (nativej.containsKey("native")) {
            nativeRequest = JSONObject.toJavaObject(nativej.getJSONObject("native"), Request.class);
        } else {
            nativeRequest = JSONObject.parseObject(nativead.getRequest(), Request.class);

        }

        Response response = new Response();
        CreativeNative creativeNative = winCampaign.getCreativeNative();

        com.gridmobi.xrtb.model.openrtbnative11.resp.Asset[] respAssets = new com.gridmobi.xrtb.model.openrtbnative11.resp.Asset[nativeRequest.getAssets().length];
        for (int i = 0; i < nativeRequest.getAssets().length; i++) {
            Asset asset = nativeRequest.getAssets()[i];
            com.gridmobi.xrtb.model.openrtbnative11.resp.Asset respasset = new com.gridmobi.xrtb.model.openrtbnative11.resp.Asset();
            respasset.setId(asset.getId());
            respasset.setRequired(asset.getRequired());
            if (asset.getImg() != null) {
                Image respImg = new Image();
                if (asset.getImg().getType() == NativeImageTypeE.ICON.code || asset.getImg().getType() == NativeImageTypeE.LOGO.code) {
                    respImg.setUrl(RtbUtil.packCreativeUrl(imp.getSecure(), creativeNative.getIconweburl()));
                    respImg.setH(creativeNative.getIconh());
                    respImg.setW(creativeNative.getIconw());
                } else if (asset.getImg().getType() == NativeImageTypeE.MAIN.code) {
                    /*
                    Small Variant: max height: at least 200 max width: at least 200, 267, or 382 aspect ratio: 1:1, 4:3, or 1.91:1
                    Large Variant: max height: at least 627 max width: at least 627, 836, or 1198 aspect ratio: 1:1, 4:3, or 1.91:1
                    */
                    if (creativeNative.getLargeimgurl() != null &&
                            creativeNative.getLarimgw() >= asset.getImg().getWmin()) {
                        respImg.setUrl(RtbUtil.packCreativeUrl(imp.getSecure(), creativeNative.getLargeimgurl()));
                        respImg.setH(creativeNative.getLarimgh());
                        respImg.setW(creativeNative.getLarimgw());
                    } else if (creativeNative.getImgw() < asset.getImg().getWmin()) {
                        respImg.setUrl(RtbUtil.packCreativeUrl(imp.getSecure(), creativeNative.getLargeimgurl()));
                        respImg.setH(creativeNative.getLarimgh());
                        respImg.setW(creativeNative.getLarimgw());
                    } else {
                        respImg.setUrl(RtbUtil.packCreativeUrl(imp.getSecure(), creativeNative.getImgweburl()));
                        respImg.setH(creativeNative.getImgh());
                        respImg.setW(creativeNative.getImgw());
                    }

                } else {
                    respImg.setUrl(RtbUtil.packCreativeUrl(imp.getSecure(), creativeNative.getLargeimgurl()));
                    respImg.setH(creativeNative.getLarimgh());
                    respImg.setW(creativeNative.getLarimgw());

                }
                respImg.setType(asset.getImg().getType());
                respasset.setImg(respImg);
            }
            if (asset.getTitle() != null) {
                Title title = new Title();
                int len = asset.getTitle().getLen();
                if (len < creativeNative.getAdtitle().length()) {

                    title.setText(creativeNative.getAdtitle().substring(0, len));
                } else {
                    title.setText(creativeNative.getAdtitle());

                }
                respasset.setTitle(title);


            }
            if (asset.getVideo() != null) {
                // if(asset.getVideo().getProtocols().toString().indexOf("2")>=0){
                if (StringUtils.isNotBlank(creativeNative.getVideoweburl())) {
                    String vast = null;

                    com.gridmobi.xrtb.model.openrtbnative11.resp.Video video = new com.gridmobi.xrtb.model.openrtbnative11.resp.Video();
                    vast = VastTemplate.vast2Native(bid, imp, impUrl, clickUrl
                            , creativeNative.getVideoduration(), creativeNative.getVideoh(), creativeNative.getVideow(), creativeNative.getVideomimes(), creativeNative.getVideoweburl());
                    video.setVasttag(vast);
                    respasset.setVideo(video);
                } else {
                    if (asset.getRequired() == 0) {
                        logger.warn("NEED VIDEO CRID:".concat(winCampaign.getCreativeNative().getId()));
                    }
                }

                //}


            }
            if (asset.getData() != null) {
                com.gridmobi.xrtb.model.openrtbnative11.resp.Data data = new com.gridmobi.xrtb.model.openrtbnative11.resp.Data();
                int type = asset.getData().getType();
                int len = asset.getData().getLen();
                if (type == NativeDataAssetTypeE.RATING.code) {
                    data.setValue(creativeNative.getAdrating() + " stars");
                } else if (type == NativeDataAssetTypeE.LIKES.code) {
                    data.setValue(creativeNative.getAdlikes() + " likes");
                } else if (type == NativeDataAssetTypeE.CTATEXT.code) {
                    data.setValue(creativeNative.getActiontext());
                } else if (type == NativeDataAssetTypeE.DESC.code) {
                    data.setValue(creativeNative.getAddesc());
                } else if (type == NativeDataAssetTypeE.DESC2.code) {
                    data.setValue(creativeNative.getAddesc());
                } else if (type == NativeDataAssetTypeE.SPONSORED.code) {
                    data.setValue(creativeNative.getAdsponsored());
                } else if (type == NativeDataAssetTypeE.SALEPRICE.code) {
                    data.setValue("$0");
                } else if (type == NativeDataAssetTypeE.PRICE.code) {
                    data.setValue("$0");
                } else {
                    data.setValue(creativeNative.getAdtitle());
                }
                if (data.getValue() == null) {

                    data.setValue(creativeNative.getAdtitle());
                }
                if (len > 0 && len < data.getValue().length()) {
                    data.setValue(data.getValue().substring(0, len));
                }
                data.setType(type);
                respasset.setData(data);

            }
            respAssets[i] = respasset;
        }
        response.setAssets(respAssets);
        response.setVer(nativeRequest.getVer());
        Link link = new Link();
        link.setUrl(clickUrl);
        response.setLink(link);
        response.setImptrackers(new String[]{impUrl});
        Map nativeAdm = Maps.newHashMap();
        nativeAdm.put("native", response);
        bid.setAdm(JSONObject.toJSONString(nativeAdm));
        bidRequest.getDspTrackLog().setCtype(String.valueOf(CreativeTypeE.NATIVE.code));


    }


    public void printReqLog(String channel, String ip, String appBundle, String os, String
            country, OpenRTB23BidRequest req, String idfa, String[] iabCats, String storeUrl, String publisher) {
        if (appBundle != null && os != null && req.getApp() != null && StringUtils.isNotBlank(country) && req.getImp() != null) {
/*            if (c % KAFKA_LOG_WEIGHT == 0) {
                //kafka logger 降频,不影响本地Log
                //kafkaBiddingLogger.requestlog(os, idfa, ip, appBundle);
            }*/
            //根据UA简单筛选一下数据
            String ua = req.getDevice().getUa() == null ? "" : req.getDevice().getUa();

/*

            if (!SimpleBidData.GEO_OS_APPS.containsKey(country)) {
                SimpleBidData.GEO_OS_APPS.put(country, Sets.newConcurrentHashSet());
            } else {
                SimpleBidData.GEO_OS_APPS.get(country).add(appBundle);
            }
*/
         /*


            ifa string ID sanctioned for advertiser use in the clear (i.e., not hashed).
                    dpidsha1 string Platform device ID (e.g., Android ID); hashed via SHA1.
                    dpidmd5 string Platform device ID (e.g., Android ID); hashed via MD5.
*/

            Device device = req.getDevice();

            try {
                if (DeviceLogUtil.LOG_GEOS.contains(country)) {
                    DeviceLogUtil.bufferedWrite(country + os, "yyyyMMddHH", JSONObject.toJSONString(device));
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
            if (device != null && device.getDevicetype() == 4) {
                StringBuilder devlog = new StringBuilder();

                devlog.append(device.getModel())
                        .append(AppConstant.LOG_SEPARATOR_SUB)
                        .append(device.getMake())
                        .append(AppConstant.LOG_SEPARATOR_SUB)
                        .append(device.getOs())
                        .append(AppConstant.LOG_SEPARATOR_SUB)
                        .append(device.getOsv())
                        .append(AppConstant.LOG_SEPARATOR_SUB)
                        .append(device.getHwv())
                        .append(AppConstant.LOG_SEPARATOR_SUB)
                        .append(device.getH())
                        .append(AppConstant.LOG_SEPARATOR_SUB)
                        .append(device.getW())
                        .append(AppConstant.LOG_SEPARATOR_SUB)
                        .append(device.getPpi())
                        .append(AppConstant.LOG_SEPARATOR_SUB)
                        .append(device.getPxratio())
                        .append(AppConstant.LOG_SEPARATOR_SUB)
                        .append(device.getFlashver())
                        .append(AppConstant.LOG_SEPARATOR_SUB)
                        .append(device.getLanguage())
                        .append(AppConstant.LOG_SEPARATOR_SUB)
                        .append(device.getCarrier())
                        .append(AppConstant.LOG_SEPARATOR_SUB)
                        .append(device.getDidsha1())
                        .append(AppConstant.LOG_SEPARATOR_SUB)
                        .append(device.getDidmd5())
                        .append(AppConstant.LOG_SEPARATOR_SUB)
                        .append(device.getMacsha1())
                        .append(AppConstant.LOG_SEPARATOR_SUB)
                        .append(device.getMacmd5())
                        .append(AppConstant.LOG_SEPARATOR_SUB)
                        .append(device.getDpidsha1());
            }
            for (Imp imp : req.getImp()) {
                int ctype = 0;
                String csize = null;
                if (imp.getVideo() != null) {
                    ctype = CreativeTypeE.VIDEO.code;
                    csize = imp.getVideo().getW() + "x" + imp.getVideo().getH();
                } else if (imp.getBanner() != null) {
                    ctype = CreativeTypeE.BANNER.code;
                    csize = imp.getBanner().getW() + "x" + imp.getBanner().getH();
                } else if (imp.getNativead() != null) {
                    ctype = CreativeTypeE.NATIVE.code;
                    csize = "";
                } else {
                    csize = "";
                }

                StringBuilder iab = new StringBuilder();
                if (iabCats == null || iabCats.length == 0) {

                } else {
                    for (String iabcat : iabCats) {
                        iab.append(iabcat).append(",");
                    }
                }
                /**
                 * 重要 ，不要改变下面的日志打印顺序和间隔，如果要改 ，请联动修改logcollect系统的 采集解析程序
                 */
                StringBuilder sublog = new StringBuilder(channel);
                sublog
                        .append(AppConstant.LOG_SEPARATOR_SUB)
                        .append(country)
                        .append(AppConstant.LOG_SEPARATOR_SUB)
                        .append(os)
                        .append(AppConstant.LOG_SEPARATOR_SUB)
                        .append(appBundle)
                        .append(AppConstant.LOG_SEPARATOR_SUB)
                        .append(publisher)
                        .append(AppConstant.LOG_SEPARATOR_SUB)
                        .append(idfa)
                        .append(AppConstant.LOG_SEPARATOR_SUB)
                        .append(device.getMake())
                        .append(AppConstant.LOG_SEPARATOR_SUB)
                        .append(ua)
                        .append(AppConstant.LOG_SEPARATOR_SUB)
                        .append(RtbUtil.get23Lang(req))
                        .append(AppConstant.LOG_SEPARATOR_SUB)
                        .append(device.getOsv())
                        .append(AppConstant.LOG_SEPARATOR_SUB)
                        .append(ip)
                        .append(AppConstant.LOG_SEPARATOR_SUB)
                        .append(device.getModel())
                        .append(AppConstant.LOG_SEPARATOR_SUB)
                        .append(device.getMccmnc() == null ? "" : device.getMccmnc())
                        .append(AppConstant.LOG_SEPARATOR_SUB)
                        .append(device.getIdfv())
                        .append(AppConstant.LOG_SEPARATOR_SUB)
                        .append(device.getOaid())
                        .append(AppConstant.LOG_SEPARATOR_SUB)
                        .append(device.getLanguage())
                        .append(AppConstant.LOG_SEPARATOR_SUB)
                        .append(System.currentTimeMillis())
                        .append(AppConstant.LOG_SEPARATOR_SUB)
                        .append(RtbUtil.get23City(req));

                collectLogger.warn(sublog.toString());

            }

        }
    }

    public SeatBid buildChnBidSeat(Bid[] bids, OpenRTB23BidRequest bidRequest) {

        SeatBid seat = new SeatBid();
        Imp[] imp = bidRequest.getImp();
        seat.setSeat(imp[0].getTagid());
        seat.setGroup(null);
        seat.setBid(bids);
        return seat;
    }

    public SeatBid buildBidSeat(Bid[] bids, OpenRTB23BidRequest bidRequest) {

        SeatBid seat = new SeatBid();
        seat.setSeat(BID_SEAT + bidRequest.getDspTrackLog().getAid());
        seat.setBid(bids);
        return seat;
    }

    public Bid buildChnBid(String impid, String channel, Campaign c, OpenRTB23BidRequest bidRequest) {

        Imp imp = getBidImp(impid, bidRequest);

        Bid bid = new Bid();
        bid.setImpid(impid);
        bid.setId(bidRequest.getId());
        bid.setAdid(c.getId().toString());
        bid.setPrice(c.getBidPrice());
//        if (c.getIabcats() != null) {
//            bid.setCat(c.getIabcats().split(","));
//        }
//        /*出价*/
//        String[] ads = {c.getAdvdomain()};
//        bid.setAdomain(ads);

//        bid.setAdid(bid.getId());

        long sl = System.currentTimeMillis();
        String stmpstr = String.valueOf(sl);
        bidRequest.getDspTrackLog().setBidstmp(stmpstr);

        String landurl = MacrosTemplate.replaceMacros(channel, c.getLandingurl(), bidRequest, c, imp, bid);
        String urlSuffixTmp = MacrosTemplate.replaceMacros(channel, new String(urlSuffix), bidRequest, c, imp, bid);
        urlSuffixTmp = urlSuffixTmp.concat("&bidstmp=").concat(stmpstr);
        String clickUrl = trackingUrl + AdTrackingType.CLICK.getFieldName() + "&" + urlSuffixTmp;
        String impUrl = trackingUrl + AdTrackingType.IMPRESSION.getFieldName() + "&" + urlSuffixTmp;

        BidExt bidExt = new BidExt();
        // 1打开网页，2下载app
        bidExt.setActionType(1);
        bidExt.setClickurl(landurl);
        List<String> impTrackers = new ArrayList<>();
        impTrackers.add(impUrl);
        bidExt.setImptrackers(impTrackers);
        List<String> clicktrackers = new ArrayList<>();
        clicktrackers.add(clickUrl);
        bidExt.setClicktrackers(clicktrackers);
        bid.setExt(bidExt);

        JSONObject ext = (JSONObject) imp.getExt();
        Integer tagtype = (Integer) ext.get("tagtype");
        // 4 为native
        if (tagtype == null || 4 == tagtype) {
//            AlgorixNativeAdmSpec nativeAdmSpec = new AlgorixNativeAdmSpec();
            Map<String, NativeAd> stringNativeAdMap = new HashMap<>();
            NativeAd nativeAd = c.getNativeAdWrapper().getNativeAd();
            stringNativeAdMap.put("native", nativeAd);
            bid.setAdm(JSON.toJSONString(stringNativeAdMap));
            com.gridmobi.xrtb.model.alg.Image img = nativeAd.getAssets()[2].getImg();
            bid.setW(img.getW());
            bid.setH(img.getH());
            bid.setIurl(img.getUrl());
            // 5为视频
        } else if (5 == tagtype) {

            Creative creative = c.getCreative();
            bid.setW(creative.getW());
            bid.setH(creative.getH());
            bid.setCrid(creative.getId());
            bid.setIurl(c.getCreative().getUrl());

            // 先设置追踪url
            List<String> dpTrackers = new ArrayList<>();  // deep link 点击跟踪链接，当deeplink被激活时请求的URL数组
            dpTrackers.add(trackingUrl + AdTrackingType.DEEP_LINK_CLICK.getFieldName() + "&" + urlSuffixTmp);
            bidExt.setDptrackers(dpTrackers);
            List<String> sdTrackers = new ArrayList<>();  // 下载开始跟踪链接，开始下载操作时请求的URL数组
            sdTrackers.add(trackingUrl + AdTrackingType.DOWNLOAD_START.getFieldName() + "&" + urlSuffixTmp);
            bidExt.setSdtrackers(sdTrackers);
            List<String> fdTrackers = new ArrayList<>();  // 下载完成跟踪链接，下载操作完成时请求的URL数组
            fdTrackers.add(trackingUrl + AdTrackingType.DOWNLOAD_FINISH.getFieldName() + "&" + urlSuffixTmp);
            bidExt.setFdtrackers(fdTrackers);
            List<String> fiTrackers = new ArrayList<>();  // 安装完成跟踪链接，应用安装完成时请求的URL数组
            fiTrackers.add(trackingUrl + AdTrackingType.INSTALL_FINISH.getFieldName() + "&" + urlSuffixTmp);
            bidExt.setFitrackers(fiTrackers);
            List<String> spTrackers = new ArrayList<>();  // 视频播放开始跟踪链接，视频开始播放时请求的URL数组
            spTrackers.add(trackingUrl + AdTrackingType.VIDEO_PLAY_START.getFieldName() + "&" + urlSuffixTmp);
            bidExt.setSptrackers(spTrackers);
            List<String> fqTrackers = new ArrayList<>();  // 视频播放1/4跟踪链接，视频播放到1/4时请求的URL数组
            fqTrackers.add(trackingUrl + AdTrackingType.VIDEO_PLAY_QUARTILE_1.getFieldName() + "&" + urlSuffixTmp);
            bidExt.setFqtrackers(fqTrackers);
            List<String> mpTrackers = new ArrayList<>();  // 视频播放1/2跟踪链接，视频播放到一半时请求的URL数组
            mpTrackers.add(trackingUrl + AdTrackingType.VIDEO_PLAY_HALF.getFieldName() + "&" + urlSuffixTmp);
            bidExt.setMptrackers(mpTrackers);
            List<String> tqTrackers = new ArrayList<>();  // 视频播放3/4跟踪链接，视频播放到3/4时请求的URL数组
            tqTrackers.add(trackingUrl + AdTrackingType.VIDEO_PLAY_QUARTILE_3.getFieldName() + "&" + urlSuffixTmp);
            bidExt.setTqtrackers(tqTrackers);
            List<String> cpTrackers = new ArrayList<>();  // 视频播放结束跟踪链接，视频播放完成时请求的URL数组
            cpTrackers.add(trackingUrl + AdTrackingType.VIDEO_PLAY_COMPLETE.getFieldName() + "&" + urlSuffixTmp);
            bidExt.setCptrackers(cpTrackers);
            // 设置adm
            AlgorixVideoAdmSpec algorixVideoAdmSpec = new AlgorixVideoAdmSpec();
            AlgorixVideoAdm algorixVideoAdm = new AlgorixVideoAdm();
            algorixVideoAdm.setDuration(creative.getVideoduration());
            algorixVideoAdm.setH(creative.getH());
            algorixVideoAdm.setW(creative.getW());
            algorixVideoAdm.setUrl(creative.getUrl());
            algorixVideoAdmSpec.setVideo(algorixVideoAdm);
            bid.setAdm(JSON.toJSONString(algorixVideoAdmSpec));

        } else {

            Creative creative = c.getCreative();
            bid.setW(creative.getW());
            bid.setH(creative.getH());
            bid.setCrid(creative.getId());

            /**
             * 如果是https 则包装https
             */
            c.getCreative().setUrl(RtbUtil.packCreativeUrl(imp.getSecure(), c.getCreative().getUrl()));

            bid.setIurl(c.getCreative().getUrl());
        }

//        offerPrice(channel, bid, imp, c, bidRequest);

        boolean chnAlg = ChannelHelper.isChnAlg(channel, bidRequest);
        String crid = (chnAlg && tagtype == 4) ? c.getNativeAdWrapper().getCreativeId() + "" : c.getCreative().getId();
        dspCounterHandler.countBid(c.getId().intValue(), crid, RtbUtil.get23Country(bidRequest), RtbUtil.get23App(bidRequest), RtbUtil.get23OS(bidRequest), ExchangesE.getCode(channel));
        return bid;
    }

    public Bid buildBid(String impid, String channel, Campaign c, OpenRTB23BidRequest bidRequest) {
//        String country = RtbUtil.get23Country(bidRequest);
//        if (country.toLowerCase().equals("chn") && channel.equalsIgnoreCase(ExchangesE.ALGORIX.key)) {
//            return buildChnBid(impid, channel, c, bidRequest,price);
//        } else {
        Imp imp = getBidImp(impid, bidRequest);

        Bid bid = new Bid();
        bid.setImpid(impid);
        bid.setId(bidRequest.getId());
        bid.setCid(c.getId().toString());
        if (c.getIabcats() != null) {
            bid.setCat(c.getIabcats().split(","));
        }
        /*出价*/
        String[] ads = {c.getAdvdomain()};
        bid.setAdomain(ads);

        bid.setAdid(bid.getId());

        /*
        生成统一时间戳 后续分库分表定位时候用到 bidstmp 字段不要去掉 很重要
         */
        long sl = System.currentTimeMillis();
        String stmpstr = String.valueOf(sl);
        bidRequest.getDspTrackLog().setBidstmp(stmpstr);

        String landurl = MacrosTemplate.replaceMacros(channel, c.getLandingurl(), bidRequest, c, imp, bid);
        String clickUrl = MacrosTemplate.replaceMacros(channel, new String(clickurlTpl), bidRequest, c, imp, bid);
        String impUrl = MacrosTemplate.replaceMacros(channel, new String(impurlTpl), bidRequest, c, imp, bid);
        String winUrl = MacrosTemplate.replaceMacros(channel, new String(winurlTpl), bidRequest, c, imp, bid);

        String impUrl2 = "";
        //如果存在自定义impr url 额外加入自定义impression


  /*       if (SimpleBidData.CAMPAIGN_IMPRURL.containsKey(bid.getCid())) {
           impUrl2 = SimpleBidData.CAMPAIGN_IMPRURL.get(bid.getCid());
            if (impUrl2.startsWith(IMP_PREFIX)) {
                impUrl2.replaceAll(IMP_PREFIX, "");
                String clickid = "DSP" + stmpstr;
                impUrl2 = MacrosTemplate.replaceTrackurl(impUrl2, bidRequest.getDspTrackLog(), clickid);
            }

        }&actualbid=${AUCTION_BID_ID}*/
        winUrl = winUrl.concat("&bidstmp=").concat(stmpstr).concat("&price=${AUCTION_PRICE}");
        impUrl = impUrl.concat("&bidstmp=").concat(stmpstr);
        clickUrl = clickUrl.concat("&bidstmp=").concat(stmpstr);
//        String sid = RtbUtil.getQuerystring(landurl);
//        clickUrl = clickUrl.concat("&sid=").concat(sid);


        if (c.getCreativeType() != null && (CreativeTypeE.NATIVE.code == c.getCreativeType())) {
            /*
            Native 广告
             */
            bid.setCrid(c.getCreativeNative().getId());
            /**
             * 如果是https 则包装https
             */
            if (StringUtils.isNotBlank(c.getCreativeNative().getImgweburl())) {

                c.getCreativeNative().setImgweburl(RtbUtil.packCreativeUrl(imp.getSecure(), c.getCreativeNative().getImgweburl()));
            }
            c.getCreativeNative().setIconweburl(RtbUtil.packCreativeUrl(imp.getSecure(), c.getCreativeNative().getIconweburl()));
            if (StringUtils.isNotBlank(c.getCreativeNative().getLargeimgurl())) {
                c.getCreativeNative().setLargeimgurl(RtbUtil.packCreativeUrl(imp.getSecure(), c.getCreativeNative().getLargeimgurl()));

            }

            if (c.getCreativeNative().getImgweburl() != null) {
                bid.setIurl(c.getCreativeNative().getImgweburl());
            } else {
                bid.setIurl(c.getCreativeNative().getIconweburl());
            }
            setNativeAdm(channel, c, bidRequest, bid, imp, clickUrl, impUrl, landurl, impUrl2);
        } else {
            /*
            非 Native 广告
             */
            bid.setCrid(c.getCreative().getId());
            bid.setH(c.getCreative().getH());
            bid.setW(c.getCreative().getW());
            /**
             * 如果是https 则包装https
             */
            c.getCreative().setUrl(RtbUtil.packCreativeUrl(imp.getSecure(), c.getCreative().getUrl()));

            bid.setIurl(c.getCreative().getUrl());
            setAdm(channel, c, bidRequest, bid, imp, clickUrl, impUrl, landurl, impUrl2);
        }
        //saveLandingUrl(bid.getId(), landurl);

        bid.setNurl(winUrl);
        offerPrice(channel, bid, imp, c, bidRequest);
        /*
        Random r = new Random();
        bid.setCid(c.getId().toString()+r.nextInt(100));
        bid.setCrid(c.getCreativeNative().getId()+r.nextInt(100));*/


        //setLurl(channel, c, bidRequest, bid, imp);

        boolean chnAlg = ChannelHelper.isChnAlg(channel, bidRequest);
        String crid = chnAlg ? c.getNativeAdWrapper().getCreativeId() + "" : c.getCreative().getId();

        dspCounterHandler.countBid(c.getId().intValue(), crid, RtbUtil.get23Country(bidRequest), RtbUtil.get23App(bidRequest), RtbUtil.get23OS(bidRequest), ExchangesE.getCode(channel));
        return bid;
    }


    public void setLurl(String channel, Campaign winCampaign, OpenRTB23BidRequest bidRequest, Bid bid, Imp imp) {

        String lUrl = MacrosTemplate.replaceMacros(channel, new String(lurlTpl), bidRequest, winCampaign, imp, bid);
        lUrl = lUrl.concat("&price=${AUCTION_PRICE}&actualbid=${AUCTION_LOSS}");
    }

    /**
     * 目前只支持如下 维度的microbid  优先级匹配根据if else逻辑
     *
     * @param bid
     * @param imp
     * @param campaign
     * @param request
     * @return
     */
    public boolean microbiding(Bid bid, Imp imp, Campaign campaign, OpenRTB23BidRequest request) {
        boolean mi = false;
        /**
         * 按顺路匹配:appbundle CPM
         */
        if (StringUtils.isNotBlank(request.getDspTrackLog().getAppbundle())) {

            String key = campaign.getId().toString()
                    .concat(AppConstant.SEPARATOR)
                    .concat(ReportGroupE.APPBUNDLE.v.toString())
                    .concat(AppConstant.SEPARATOR)
                    .concat(request.getDspTrackLog().getAppbundle());

            Float microbid = SimpleBidData.MICRO_BID.get(key);
            if (microbid != null && microbid >= 0) {
                bid.setPrice(microbid);
                return true;
            }

        }
        /**
         * 按顺路匹配:publiser CPM
         */
        if (StringUtils.isNotBlank(request.getDspTrackLog().getPubid())) {

            String key = campaign.getId().toString()
                    .concat(AppConstant.SEPARATOR)
                    .concat(ReportGroupE.PUBLISHER.v.toString())
                    .concat(AppConstant.SEPARATOR)
                    .concat(request.getDspTrackLog().getPubid());

            Float microbid = SimpleBidData.MICRO_BID.get(key);
            if (microbid != null && microbid >= 0) {
                bid.setPrice(microbid);
                return true;
            }

        }
        /**
         * 按顺路匹配:素材ID CPM
         */
        if (StringUtils.isNotBlank(bid.getCrid())) {

            String key = campaign.getId().toString()
                    .concat(AppConstant.SEPARATOR)
                    .concat(ReportGroupE.CRID.v.toString())
                    .concat(AppConstant.SEPARATOR)
                    .concat(bid.getCrid());

            Float microbid = SimpleBidData.MICRO_BID.get(key);
            if (microbid != null && microbid >= 0) {
                bid.setPrice(microbid);
                return true;
            }

        }

        /**
         * 按顺路匹配:素材尺寸 CPM ,video html  native 暂时没有尺寸，虽然视频html 也都有size
         */


        if (campaign.getCreativeType() != null) {
            String ctype = campaign.getCreativeType().toString();
        /*    if(campaign.getSecondCreativeType()!=campaign.getCreativeType().intValue()){
                ctype = String.valueOf(campaign.getSecondCreativeType());
            }*/
            String key = campaign.getId().toString()
                    .concat(AppConstant.SEPARATOR)
                    .concat(ReportGroupE.CTYPE.v.toString())
                    .concat(AppConstant.SEPARATOR)
                    .concat(ctype);

            Float microbid = SimpleBidData.MICRO_BID.get(key);
            if (microbid != null && microbid >= 0) {
                bid.setPrice(microbid);
                return true;
            }

        }

        if (campaign.getCreativeType() != null && campaign.getCreative() != null
                && campaign.getCreativeType().intValue() != CreativeTypeE.NATIVE.code
                && StringUtils.isNotBlank(campaign.getCreative().getSize())) {

            String key = campaign.getId().toString()
                    .concat(AppConstant.SEPARATOR)
                    .concat(ReportGroupE.CSIZE.v.toString())
                    .concat(AppConstant.SEPARATOR)
                    .concat(campaign.getCreative().getSize());

            Float microbid = SimpleBidData.MICRO_BID.get(key);
            if (microbid != null && microbid >= 0) {
                bid.setPrice(microbid);
                return true;
            }

        }

        if (StringUtils.isNotBlank(request.getDspTrackLog().getChannel())) {

            String key = campaign.getId().toString()
                    .concat(AppConstant.SEPARATOR)
                    .concat(ReportGroupE.CHANNEL.v.toString())
                    .concat(AppConstant.SEPARATOR)
                    .concat(request.getDspTrackLog().getChannel());

            Float microbid = SimpleBidData.MICRO_BID.get(key);
            if (microbid != null && microbid >= 0) {
                bid.setPrice(microbid);
                return true;
            }

        }
        if (StringUtils.isNotBlank(request.getDspTrackLog().getCarrier())) {

            String key = campaign.getId().toString()
                    .concat(AppConstant.SEPARATOR)
                    .concat(ReportGroupE.CARRIER.v.toString())
                    .concat(AppConstant.SEPARATOR)
                    .concat(request.getDspTrackLog().getCarrier());

            Float microbid = SimpleBidData.MICRO_BID.get(key);
            if (microbid != null && microbid >= 0) {
                bid.setPrice(microbid);
                return true;
            }

        }

        return mi;
    }


    /**
     * 全局黑名单，目前只支持 appbundle pub  ip  devid 四个维度
     *
     * @param request
     * @return
     */
    public boolean isBlockList(OpenRTB23BidRequest request) {
        String key = null;
        if (StringUtils.isNotBlank(request.getDspTrackLog().getIp())) {

            key = ReportGroupE.IP.v.toString().concat(AppConstant.SEPARATOR).concat(request.getDspTrackLog().getIp());
            boolean res = SimpleBidData.BLOCK_LIST.contains(key);
            if (res) {
                return res;
            }

        }

        if (StringUtils.isNotBlank(request.getDspTrackLog().getAppbundle())) {

            key = ReportGroupE.APPBUNDLE.v.toString().concat(AppConstant.SEPARATOR).concat(request.getDspTrackLog().getAppbundle());
            boolean res = SimpleBidData.BLOCK_LIST.contains(key);
            if (res) {
                return res;
            }

        }


        if (StringUtils.isNotBlank(request.getDspTrackLog().getPubid())) {

            key = ReportGroupE.PUBLISHER.v.toString().concat(AppConstant.SEPARATOR).concat(request.getDspTrackLog().getPubid());
            boolean res = SimpleBidData.BLOCK_LIST.contains(key);
            if (res) {
                return res;
            }

        }

        if (StringUtils.isNotBlank(request.getDspTrackLog().getDevid())) {

            key = ReportGroupE.DEVID.toString().concat(AppConstant.SEPARATOR).concat(request.getDspTrackLog().getDevid());
            boolean res = SimpleBidData.BLOCK_LIST.contains(key);
            if (res) {
                return res;
            }
        }

        return false;
    }

    public BidHandler rules(OpenRTB23BidRequest req) throws Exception {
        return this;
    }

    /**
     * 根据策略以及CTR等选出活动
     *
     * @param matchlist
     * @param bidRequest
     * @return
     */
    public Campaign electCampaign(List<Campaign> matchlist, OpenRTB23BidRequest bidRequest) {
        Random r = new Random();
        Campaign c = matchlist.get(r.nextInt(matchlist.size()));
        bidRequest.getDspTrackLog().setAid(c.getAid().toString());
        bidRequest.getDspTrackLog().setLabelid(c.getLabelid().toString());
        return c;
    }

    /**
     * 根据策略以及CTR等选出活动
     *
     * @param matchlist
     * @param bidRequest
     * @return
     */
    public Creative electCreative(List<Creative> matchlist, OpenRTB23BidRequest bidRequest) {
        Random r = new Random();
        Creative c = matchlist.get(r.nextInt(matchlist.size()));
        bidRequest.getDspTrackLog().setPos(String.valueOf(c.getImpadpos()));
        return c;
    }

    public CreativeNative electNativeCreative(List<CreativeNative> matchlist, OpenRTB23BidRequest bidRequest) {
        Random r = new Random();
        CreativeNative c = matchlist.get(r.nextInt(matchlist.size()));
        return c;
    }

    public static Float calcPrice(Campaign winCampaign, OpenRTB23BidRequest bidRequest) {
//        System.out.println(channel + ":" + bidRequest.getAt() + ":" + bidRequest.getDspTrackLog().getGeo() + ":" + bidRequest.getDspTrackLog().getOs());
        Imp imp = bidRequest.getImp()[0];
        //二次出价模式是根据低价报价,一次出价模式 是一口价
        Random random = new Random();
        float v = random.nextFloat() + random.nextInt(2);
//        v = v>0.7?v-0.7f:v;
        if (bidRequest.getAt() == 1) {
//
            if (random.nextInt(10) < 2) {
                return winCampaign.getBuyingprice() + v;

            } else {
                return imp.getBidfloor() + v;
            }

        } else {

            int i = random.nextInt(100);
            if (i < 60) {
                return imp.getBidfloor() + 0.0001f;
            } else if (i < 70) {
                return imp.getBidfloor() + 0.0002f;
            } else if (i < 80) {
                return imp.getBidfloor() + 0.0003f;
            } else if (i < 90) {
                return imp.getBidfloor() + 0.0004f;
            } else {
                return imp.getBidfloor() + 0.0005f;
            }

        }

    }


    /**
     * 出价策略以及CTR等选出活动
     *
     * @param winCampaign
     * @param bidRequest
     * @return
     */
    public Float offerPrice(String channel, Bid bid, Imp imp, Campaign winCampaign, OpenRTB23BidRequest bidRequest) {
        System.out.println(channel + ":" + bidRequest.getAt() + ":" + bidRequest.getDspTrackLog().getGeo() + ":" + bidRequest.getDspTrackLog().getOs());

        //二次出价模式是根据低价报价,一次出价模式 是一口价
        if (bidRequest.getAt() == 1) {

            if (random.nextInt(2) == 0) {
                bid.setPrice(winCampaign.getBuyingprice() + 0.1f);

            } else {

                bid.setPrice(imp.getBidfloor() + 0.1f);

            }

        } else {
            if (random.nextInt(2) == 0) {
                bid.setPrice(winCampaign.getBuyingprice() + 0.1f);

            } else {

                bid.setPrice(imp.getBidfloor() + 0.1f);

            }

        }

        return bid.getPrice();
    }

    public Imp getBidImp(String impid, OpenRTB23BidRequest bidRequest) {
        /**
         * 获取当前竞价IMP
         */
        Imp[] imps = bidRequest.getImp();
        Imp bidImp = null;
        for (Imp imp : imps) {
            if (impid.equalsIgnoreCase(imp.getId())) {
                bidImp = imp;
                break;
            }
        }
        return bidImp;
    }

    public Set<Integer> querySchehoursByCid(int d, String cid) {
        Set<Integer> hours = new HashSet<>();
        try {
            BooleanQuery.Builder builderSche = new BooleanQuery.Builder();
            builderSche.add(new TermQuery(new Term("d", String.valueOf(d))), BooleanClause.Occur.MUST);
            builderSche.add(new TermQuery(new Term("cid", cid)), BooleanClause.Occur.MUST);

            IndexReader readerSche = DirectoryReader.open(BidIndex.CAMPAIGNS_SCHE_W);
            IndexSearcher searcherSche = new IndexSearcher(readerSche);
            Query queryChe = new ConstantScoreQuery(builderSche.build()).getQuery();
            TopDocs resultsSche = searcherSche.search(queryChe, Integer.MAX_VALUE);

            ScoreDoc[] hitsSche = resultsSche.scoreDocs;
            for (ScoreDoc scoreDoc : hitsSche) {
                Document doc = searcherSche.doc(scoreDoc.doc);
                String st = doc.get("st");
                String et = doc.get("et");
                IntStream.range(Integer.parseInt(st), Integer.parseInt(et) + 1).forEach(i -> hours.add(i));
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return hours;

    }


}
